package com.aw.baselib.net.api

import android.content.Context
import com.aw.baselib.net.SSLSocketClient
import com.aw.baselib.net.gson.NullOnEmptyConverterFactory
import com.aw.baselib.util.AwLog.d
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.TypeAdapter
import com.google.gson.TypeAdapterFactory
import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.io.IOException
import java.security.KeyStore
import java.security.SecureRandom
import java.security.cert.CertificateFactory
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManagerFactory

/**
 * Created by hzw
 */
abstract class RetrofitClient protected constructor() {
    fun builderRetrofit(baseUrl: String?): Retrofit {
        val gson =
            GsonBuilder().registerTypeAdapterFactory(NullToDefaultValueAdapterFactory<Any?>())
                .create()
        val builder = Retrofit.Builder()
        builder.baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create(gson)) //                    .addConverterFactory(CustomGsonConverterFactory.create(gson))
            .addConverterFactory(NullOnEmptyConverterFactory())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .client(setClient().build())
            .build()
        return builder.build()
    }

    /**
     * 设置OkHttpClient，添加拦截器等
     *
     * @return 可以返回为null
     */
    protected abstract fun setClient(): OkHttpClient.Builder
    private class NullToDefaultValueAdapterFactory<T> : TypeAdapterFactory {
        override fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
            val rawType = type.rawType as Class<T>
            if (rawType == String::class.java) {
                return StringNullAdapter() as TypeAdapter<T>
            } else if (rawType == Boolean::class.java) {
                return BooleanNullAdapter() as TypeAdapter<T>
            } else if (rawType == Int::class.java) {
                return IntegerNullAdapter() as TypeAdapter<T>
            } else if (rawType == Double::class.java) {
                return DoubleNullAdapter() as TypeAdapter<T>
            } else if (rawType == Long::class.java) {
                return LongNullAdapter() as TypeAdapter<T>
            }
            return null
        }
    }

    private class LongNullAdapter : TypeAdapter<Long?>() {
        @Throws(IOException::class)
        override fun read(reader: JsonReader): Long? {
            if (reader.peek() == JsonToken.NULL) {
                reader.nextNull()
                return 0L
            }
            return reader.nextLong()
        }

        @Throws(IOException::class)
        override fun write(writer: JsonWriter, value: Long?) {
            if (value == null) {
                writer.nullValue()
                return
            }
            writer.value(value)
        }
    }

    private class DoubleNullAdapter : TypeAdapter<Double?>() {
        @Throws(IOException::class)
        override fun read(reader: JsonReader): Double? {
            if (reader.peek() == JsonToken.NULL) {
                reader.nextNull()
                return 0.0
            }
            var doubleValue = 0.0
            doubleValue = try {
                val stringValue = reader.nextString()
                stringValue.toDouble()
            } catch (e: NumberFormatException) {
                return 0.0
            }
            return doubleValue
        }

        @Throws(IOException::class)
        override fun write(writer: JsonWriter, value: Double?) {
            if (value == null) {
                writer.nullValue()
                return
            }
            writer.value(value)
        }
    }

    private class IntegerNullAdapter : TypeAdapter<Int?>() {
        @Throws(IOException::class)
        override fun read(reader: JsonReader): Int? {
            if (reader.peek() == JsonToken.NULL) {
                reader.nextNull()
                return 0
            }
            return reader.nextInt()
        }

        @Throws(IOException::class)
        override fun write(writer: JsonWriter, value: Int?) {
            if (value == null) {
                writer.nullValue()
                return
            }
            writer.value(value)
        }
    }

    private class BooleanNullAdapter : TypeAdapter<Boolean?>() {
        @Throws(IOException::class)
        override fun read(reader: JsonReader): Boolean? {
            if (reader.peek() == JsonToken.NULL) {
                reader.nextNull()
                return false
            }
            return reader.nextBoolean()
        }

        @Throws(IOException::class)
        override fun write(writer: JsonWriter, value: Boolean?) {
            if (value == null) {
                writer.nullValue()
                return
            }
            writer.value(value)
        }
    }

    private class StringNullAdapter : TypeAdapter<String?>() {
        @Throws(IOException::class)
        override fun read(reader: JsonReader): String? {
            if (reader.peek() == JsonToken.NULL) {
                reader.nextNull()
                return ""
            }
            return reader.nextString()
        }

        @Throws(IOException::class)
        override fun write(writer: JsonWriter, value: String?) {
            if (value == null) {
                writer.nullValue()
                return
            }
            writer.value(value)
        }
    }

    companion object {
        val okhttp: OkHttpClient.Builder
            get() {
                val httpClient = OkHttpClient.Builder()
                val requestParamInterceptor = UrlInterceptor()
                val logging = HttpLoggingInterceptor { message ->
                    d(
                        "okHttpLog: $message"
                    )
                }
                //HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> Log.d("RetrofitLog", message));
                logging.level = HttpLoggingInterceptor.Level.BODY
                httpClient.addInterceptor(logging)
                httpClient.connectTimeout(60, TimeUnit.SECONDS)
                httpClient.readTimeout(60, TimeUnit.SECONDS)
                httpClient.writeTimeout(60, TimeUnit.SECONDS)
                httpClient.addNetworkInterceptor(requestParamInterceptor)
                httpClient.sslSocketFactory(SSLSocketClient.sSLSocketFactory)
                httpClient.hostnameVerifier(SSLSocketClient.hostnameVerifier)
                //加入https的证书
                /*      int[] certficates = new int[]{R.raw.app_key};
        SSLSocketFactory sslSocketFactory = getSSLSocketFactory(AppContext.getContext(), certficates);
        if (sslSocketFactory != null) {
            httpClient.sslSocketFactory(sslSocketFactory);
        }
*/return httpClient
            }

        fun getSSLSocketFactory(context: Context?, certificates: IntArray): SSLSocketFactory? {
            if (context == null) {
                throw NullPointerException("context == null")
            }

            //CertificateFactory用来证书生成
            val certificateFactory: CertificateFactory
            try {
                certificateFactory = CertificateFactory.getInstance("X.509")
                //Create a KeyStore containing our trusted CAs
                val keyStore = KeyStore.getInstance(KeyStore.getDefaultType())
                keyStore.load(null, null)
                for (i in certificates.indices) {
                    //读取本地证书
                    val `is` = context.resources.openRawResource(certificates[i])
                    keyStore.setCertificateEntry(
                        i.toString(),
                        certificateFactory.generateCertificate(`is`)
                    )
                    if (`is` != null) {
                        `is`.close()
                    }
                }
                //Create a TrustManager that trusts the CAs in our keyStore
                val trustManagerFactory =
                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
                trustManagerFactory.init(keyStore)

                //Create an SSLContext that uses our TrustManager
                val sslContext = SSLContext.getInstance("TLS")
                sslContext.init(null, trustManagerFactory.trustManagers, SecureRandom())
                return sslContext.socketFactory
            } catch (e: Exception) {
            }
            return null
        }
    }
}